using System;
using OracleInternal.Json.Common;
using OracleInternal.Json.Sql;

namespace OracleInternal.Json.Binary
{
	internal class OsonAbstractObject : OsonStructure
	{
		private bool m_fidSorted;

		private int m_fidArrayOffset;

		internal OsonAbstractObject(OsonContext ctx)
			: base(ctx)
		{
		}

		internal OsonAbstractObject(OsonContext ctx, int pos)
			: base(ctx)
		{
			Init(pos);
		}

		public override OracleJsonType GetOracleJsonType()
		{
			return OracleJsonType.OBJECT;
		}

		internal OsonAbstractArray GetJsonArrayInternal(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return null;
			}
			return GetArrayInternal(childOffset);
		}

		internal OsonAbstractObject GetJsonObjectInternal(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return null;
			}
			return GetJsonObjectInternal(childOffset);
		}

		internal string GetJsonString(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return GetStringInternal(childOffset) ?? throw new InvalidCastException();
		}

		internal string GetJsonString(string key, string d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			string stringInternal = GetStringInternal(childOffset);
			if (stringInternal == null)
			{
				return d;
			}
			return stringInternal;
		}

		internal bool GetBoolean(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return GetBooleanInternal(childOffset);
		}

		internal bool GetBoolean(string key, bool d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			bool booleanInternal = GetBooleanInternal(childOffset);
			if (!booleanInternal)
			{
				return d;
			}
			return booleanInternal;
		}

		internal int GetInt(string key, int d)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				return d;
			}
			object valueInternal = GetValueInternal(childOffset);
			if (!(valueInternal is OracleJsonNumber))
			{
				return d;
			}
			return ((OracleJsonNumber)valueInternal).IntValue();
		}

		internal int GetInt(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return ((OracleJsonNumber)GetValueInternal(childOffset)).IntValue();
		}

		internal bool IsNull(string key)
		{
			int childOffset = GetChildOffset(key);
			if (childOffset == -1)
			{
				throw new NullReferenceException();
			}
			return IsNullInternal(childOffset);
		}

		internal bool ContainsKey(object key)
		{
			if (key is string)
			{
				return GetChildOffset((string)key) != -1;
			}
			return false;
		}

		internal object GetInternal(object key)
		{
			if (!(key is string))
			{
				return null;
			}
			int childOffset = GetChildOffset((string)key);
			if (childOffset < 0)
			{
				return null;
			}
			return GetValueInternal(childOffset);
		}

		protected override void Init(int pos)
		{
			base.Init(pos);
			int uB = m_ctx.m_osonBuffer.GetUB1(pos);
			InitChildOffseUb(uB);
			m_fidArrayOffset = pos + 1;
			int num = uB & 0x18;
			OsonHeader header = m_ctx.GetHeader();
			switch (num)
			{
			case 0:
				m_size = m_ctx.m_osonBuffer.GetUB1(pos + 1);
				m_fidArrayOffset++;
				m_childArrayOffset = m_fidArrayOffset + m_size * header.NumFieldIdBytes();
				break;
			case 8:
				m_size = m_ctx.m_osonBuffer.GetUB2(pos + 1);
				m_fidArrayOffset += 2;
				m_childArrayOffset = m_fidArrayOffset + m_size * header.NumFieldIdBytes();
				break;
			case 16:
				m_size = m_ctx.m_osonBuffer.GetUB4int(pos + 1);
				m_fidArrayOffset += 4;
				m_childArrayOffset = m_fidArrayOffset + m_size * header.NumFieldIdBytes();
				break;
			case 24:
			{
				int num2;
				if (m_childOffsetUb == 4)
				{
					num2 = m_ctx.m_osonBuffer.GetUB4int(pos + 1) + header.GetTreeSegmentOffset();
					m_childArrayOffset = pos + 1 + 4;
				}
				else
				{
					num2 = m_ctx.m_osonBuffer.GetUB2(pos + 1) + header.GetTreeSegmentOffset();
					m_childArrayOffset = pos + 1 + 2;
				}
				int num3 = m_ctx.m_osonBuffer.GetUB1(num2) & 0x18;
				m_fidArrayOffset = num2 + 1;
				switch (num3)
				{
				case 0:
					m_size = m_ctx.m_osonBuffer.GetUB1(num2 + 1);
					m_fidArrayOffset++;
					break;
				case 8:
					m_size = m_ctx.m_osonBuffer.GetUB2(num2 + 1);
					m_fidArrayOffset += 2;
					break;
				case 16:
					m_size = m_ctx.m_osonBuffer.GetUB4int(num2 + 1);
					m_fidArrayOffset += 4;
					break;
				default:
					throw new IllegalStateException(string.Empty);
				}
				break;
			}
			}
			m_fidSorted = (uB & 4) == 0 && header.FieldsSorted();
		}

		protected override int GetChildOffset(int fieldPos)
		{
			OsonHeader header = m_ctx.GetHeader();
			if (m_childOffsetUb == 2)
			{
				return m_ctx.m_osonBuffer.GetUB2(m_childArrayOffset + fieldPos * 2) + header.GetTreeSegmentOffset();
			}
			return m_ctx.m_osonBuffer.GetUB4int(m_childArrayOffset + fieldPos * 4) + header.GetTreeSegmentOffset();
		}

		protected int GetChildOffset(string key)
		{
			int childPosition = GetChildPosition(key);
			if (childPosition == -1)
			{
				return -1;
			}
			return GetChildOffset(childPosition);
		}

		protected int GetChildPosition(string key)
		{
			OsonHeader header = m_ctx.GetHeader();
			int fieldId = header.GetFieldId(key);
			if (fieldId == -1)
			{
				return -1;
			}
			m_ctx.m_osonBuffer.Position(m_pos + 1);
			int num = ((header.NumFieldIdBytes() == 1) ? ((!m_fidSorted) ? m_ctx.m_osonBuffer.LinearSearchUb1(m_fidArrayOffset, m_size, fieldId) : m_ctx.m_osonBuffer.BinarySearchUb1(m_fidArrayOffset, m_size, fieldId)) : ((header.NumFieldIdBytes() == 2) ? ((!m_fidSorted) ? m_ctx.m_osonBuffer.LinearSearchUb2(m_fidArrayOffset, m_size, fieldId) : m_ctx.m_osonBuffer.BinarySearchUb2(m_fidArrayOffset, m_size, fieldId)) : ((!m_fidSorted) ? m_ctx.m_osonBuffer.LinearSearchUb4(m_fidArrayOffset, m_size, fieldId) : m_ctx.m_osonBuffer.BinarySearchUb4(m_fidArrayOffset, m_size, fieldId))));
			if (num < 0)
			{
				return -1;
			}
			return num;
		}

		internal string GetFieldName(int child)
		{
			OsonHeader header = m_ctx.GetHeader();
			int num = ((header.NumFieldIdBytes() == 1) ? m_ctx.m_osonBuffer.GetUB1(m_fidArrayOffset + child) : ((header.NumFieldIdBytes() != 2) ? m_ctx.m_osonBuffer.GetUB4int(m_fidArrayOffset + child * 4) : m_ctx.m_osonBuffer.GetUB2(m_fidArrayOffset + child * 2)));
			return header.fieldNames[num - 1];
		}
	}
}
